﻿#region Header
// Copyright 2007-2011, Jerónimo Milea
// 
// This file is part of NetJsWire.
// 
//     NetJsWire is free software: you can redistribute it and/or modify
//     it under the terms of the GNU General Public License as published by
//     the Free Software Foundation, either version 3 of the License, or
//     (at your option) any later version.
// 
//     NetJsWire is distributed in the hope that it will be useful,
//     but WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//     GNU General Public License for more details.
// 
//     You should have received a copy of the GNU General Public License
//     along with NetJsWire.  If not, see <http://www.gnu.org/licenses/>.
#endregion

using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.Serialization;
using System.Windows.Forms;
using NetJsWire.Lite.Converters;
using NetJsWire.Lite.Designers;
using NetJsWire.Lite.Properties;
using NetJsWire.Lite.Widgets.UI.Data;
using NetJsWire.Lite.Widgets.UI.Layout;
using Newtonsoft.Json;

namespace NetJsWire.Lite.Widgets.UI.Grid
{
    [JsonObject( MemberSerialization = MemberSerialization.OptIn )]
    [Designer( typeof( GridPanelDesigner ) )]
    [Serializable]
    [DefaultProperty( "ColumnModel" )]
    public class GridPanel : Panel
    {
        internal static int ColumnsBarHeight;// = 25;
        private ColumnModel _columnModel;
        private Store _store;

        public GridPanel()
            : this( null )
        {
        }

        public GridPanel( IContainer container )
            : base( container )
        {
            base.Xtype = "grid";

            if ( Settings.Default != null )
            {
                DefaultBackgroundColor = Settings.Default.GridBackgroundColor;
                ColumnsBarHeight = Settings.Default.GridColumnsBarHeight;
            }

            base.BackColor = DefaultBackgroundColor;
            BackgroundColor = DefaultBackgroundColor;
            _columnModel = new ColumnModel( this );
        }

        [Browsable( true )]
        [DesignerSerializationVisibility( DesignerSerializationVisibility.Content )]
        [JsonProperty( "cm" )]
        [TypeConverter( typeof( ExpandableObjectConverter ) )]
        public ColumnModel ColumnModel
        {
            get { return _columnModel; }
            set { _columnModel = value; }
        }

        [DefaultValue( false )]
        [JsonProperty( "loadMask" )]
        public bool LoadMask { get; set; }

        [Browsable( true )]
        [JsonProperty( "store" )]
        [DefaultValue( null )]
        public Store Store
        {
            get { return _store; }
            set
            {
                _store = value;
                if ( _store == null || ColumnModel == null || !_store.ShouldSerializeFields() ||
                     ColumnModel.ShouldSerializeColumns() ) return;
                foreach ( var field in _store.Fields )
                {
                    ColumnModel.Columns.Add( GetColumnFromField( field, ColumnModel ) );
                }
                InvalidateWindow();
            }
        }

        [Browsable( true )]
        [JsonProperty( "autoExpandColumn", DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore )]
        [DefaultValue( ( string ) null )]
        [Description( "The id of a column in this grid that should expand to fill unused space. This value specified here can not be 0.\nNote: If the Grid's view is configured with forceFit=true the autoExpandColumn is ignored." )]
        public string AutoExpandColumn { get; set; }

        [JsonProperty( "stripeRows", DefaultValueHandling = DefaultValueHandling.Ignore )]
        [Browsable( true )]
        [DefaultValue( false )]
        public bool StripeRows { get; set; }

        [JsonProperty( "sm", DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore )]
        [JsonConverter( typeof( SelectionModelJsonConverter ) )]
        [Browsable( true )]
        [DefaultValue( null )]
        public SelectionModel SelectionModel { get; set; }

        [Browsable( true )]
        [JsonProperty( "view" )]
        [DefaultValue( null )]
        public GridView View { get; set; }

        [Browsable( false )]
        [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
        [EditorBrowsable( EditorBrowsableState.Never )]
        public override LayoutType Layout
        {
            get
            {
                return base.Layout;
            }
            set
            {
                base.Layout = value;
            }
        }

        public bool ShouldSerializeColumnModel()
        {
            return ColumnModel.ShouldSerializeColumns() || ColumnModel.ShouldSerializeListeners() || ColumnModel.ShouldSerializeDefaults();
        }

        [OnSerializing]
        internal void OnSerializingMethod( StreamingContext context )
        {
            if ( SelectionModel is CheckboxSelectionModel )
            {
                var win = FindWindow();
                if ( win != null )
                {
                    win.InternalPreCode = string.Format( "var {0}=new Ext.grid.CheckboxSelectionModel({1});{2}", ( SelectionModel as CheckboxSelectionModel ).VarName, JsonConvert.SerializeObject( SelectionModel, SerializationFormating, new ListenerCollectionJsonConverter() ), win.InternalPreCode );
                }
            }
        }

        protected override void OnNonClientAreaCalcSize( ref Rectangle bounds, bool update )
        {
            base.OnNonClientAreaCalcSize( ref bounds, update );
            //var topHeight = !string.IsNullOrWhiteSpace( Title ) && ( ( Container ) Parent ).Layout != LayoutType.Card ? TitleBarHeight : 0;
            var topHeight = ColumnModel.ShouldSerializeColumns() ? ColumnsBarHeight : 0;
            //if ( ColumnModel.ShouldSerializeColumns() )
            //{
            //    topHeight += COLUMNS_BAR_HEIGHT;
            //}
            var clientPadding = new Padding( 0, topHeight, 0, 0 );
            //var clientPadding = new Padding( BorderWidth, topHeight + BorderWidth, BorderWidth, DrawButtonsBar ? ButtonsBarHeight + BorderWidth : BorderWidth );
            bounds = new Rectangle( bounds.Left + clientPadding.Left, bounds.Top + clientPadding.Top,
                bounds.Width - clientPadding.Horizontal, bounds.Height - clientPadding.Vertical );
        }

        protected override void OnPaintNcArea( PaintEventArgs e )
        {
            base.OnPaintNcArea( e );

            if ( !ColumnModel.ShouldSerializeColumns() )
                return;

            var topHalf = Color.FromArgb( 249, 249, 249 );
            var bottomHalf = Color.FromArgb( 242, 242, 242 );
            var outerBorder = Color.FromArgb( 220, 220, 220 );
            var borderWidth = Border ? 1 : 0;
            var colBarRect = new Rectangle( e.ClipRectangle.X + borderWidth, e.ClipRectangle.Y + borderWidth + ( !string.IsNullOrEmpty( Title ) ? TitleBarHeight + 1 : 0 ), e.ClipRectangle.Width - ( borderWidth * 2 ), ColumnsBarHeight );
            if ( Parent != null && ( ( Container ) Parent ).Layout == LayoutType.Card )
            {
                colBarRect.Y -= TitleBarHeight + 1;
            }
            using ( var br = new SolidBrush( topHalf ) )
            {
                e.Graphics.FillRectangle( br, colBarRect.X, colBarRect.Y, colBarRect.Width, ( colBarRect.Height / 2 ) - ( 1 + ( borderWidth * 2 ) ) );

            }
            using ( var br = new SolidBrush( bottomHalf ) )
            {
                e.Graphics.FillRectangle( br, colBarRect.X, colBarRect.Y + ( colBarRect.Height / 2 ) - 3, colBarRect.Width, ( colBarRect.Height / 2 ) + ( 1 + ( borderWidth * 2 ) ) + ( ( Parent != null && ( ( Container ) Parent ).Layout == LayoutType.Card ) ? 1 : 0 ) );
            }

            using ( var pen = new Pen( outerBorder ) )
            {
                e.Graphics.DrawLine( pen, colBarRect.X + borderWidth, colBarRect.Y + ColumnsBarHeight - 1, colBarRect.X + colBarRect.Width - ( borderWidth * 2 ), colBarRect.Y + ColumnsBarHeight - 1 );
            }

            var startX = 0;
            foreach ( var column in ColumnModel.Columns )
            {
                //e.Graphics.FillRectangle( Brushes.AntiqueWhite, e.ClipRectangle.X + 4, e.ClipRectangle.Y + 4 + Panel.TITLE_BAR_HEIGHT + 2, column.Width, 23 );
                if ( !column.Hidden )
                {
                    using ( var pen = new Pen( outerBorder ) )
                    {
                        e.Graphics.DrawLine( pen, colBarRect.X + startX + column.Width, colBarRect.Y, colBarRect.X + startX + column.Width, colBarRect.Y + ColumnsBarHeight - 1 );
                    }

                    using ( var pen = new Pen( Color.White ) )
                    {
                        e.Graphics.DrawLine( pen, colBarRect.X + startX + 1, colBarRect.Y, colBarRect.X + startX + 1, colBarRect.Y + ColumnsBarHeight );
                    }

                    using ( var font = new Font( "Arial", 11, FontStyle.Regular, GraphicsUnit.Pixel ) )
                    {
                        using ( var br = new SolidBrush( Color.Black ) )
                        {
                            var textSize = e.Graphics.MeasureString( column.Header, font );
                            e.Graphics.DrawString( column.Header, font, br, colBarRect.X + 4 + startX, colBarRect.Y + ( ( ColumnsBarHeight + 1 ) / 2 ) - textSize.Height / 2 );
                        }
                    }
                    startX += column.Width;
                }
            }
        }

        private static Column GetColumnFromField( Field field, ColumnModel model )
        {
            switch ( field.Type )
            {
                case "boolean":
                    return new BooleanColumn( model ) { Name = field.Name, Header = field.Name, DataIndex = field.Mapping ?? field.Name };
                case "int":
                case "float":
                    return new NumberColumn( model ) { Name = field.Name, Header = field.Name, DataIndex = field.Mapping ?? field.Name };
                case "date":
                    return new DateColumn( model ) { Name = field.Name, Header = field.Name, DataIndex = field.Mapping ?? field.Name };
                default:
                    return new Column( model ) { Name = field.Name, Header = field.Name, DataIndex = field.Mapping ?? field.Name };
            }
        }

    }
}
